<template>
  <div class="scene" id="scene">
    <div class="tree_utils">
      <div class="ver_line"></div>
      <div style="display: inline-block">
        <div class="items" @mouseenter="showDetail" @mouseleave="closeDetail">
          <QuestionCircleOutlined />
        </div>
        <div class="ver_line"></div>
      </div>
      <div style="display: inline-block">
        <div class="items">
          <a-upload name="file" maxCount="1" multiple="false" fileList="" @change="changeFile">
            <a-button> 选择模型文件 </a-button>
          </a-upload>
        </div>
        <div class="ver_line"></div>
      </div>
      <div ref="mtlSearcher" style="display: none">
        <div class="items">
          <a-upload name="file" maxCount="1" multiple="false" fileList="" @change="changeMtlFile">
            <a-button> 选择材质文件 </a-button>
          </a-upload>
        </div>
        <div class="ver_line"></div>
      </div>
    </div>
    <div
      ref="treeDiv"
      class="tree_class"
      @mousedown="mousedown"
      @mousemove="mousemove"
      @mouseup="mouseup"
    >
      <div class="tree_title">构件树</div>
      <div class="tree_content">
        <Tree
          v-if="componentTree"
          v-model:checkedKeys="checkedKeys"
          @check="checkItems"
          :selectable="false"
          checkable
          :tree-data="componentTree"
        >
          <template #title="{ title, key }">
            <span>{{ title }}</span>
          </template>
        </Tree>
      </div>
    </div>
    <div ref="detailRef" class="detail">
      <p style="width: 100%; text-align: center">说明</p>
      1、当前DEMO支持以下类型模型文件：glb、gltf、obj（+mtl）、fbx。注意：obj（+mtl）格式不支持本地贴图文件的加载<br />
      2、点选构件树可以控制模型构件的显示与隐藏<br />
      3、点选构件高亮显示，右侧图形用户界面可以控制高亮样式<br />
    </div>
    <div class="tag" id="tag"> </div>
  </div>
</template>
<script lang="ts">
  import { QuestionCircleOutlined } from '@ant-design/icons-vue';
  import { Tree } from 'ant-design-vue';
  import { Base3d } from './utils/Base3d';
  import { defineComponent, ref, onMounted, onBeforeUnmount } from 'vue';
  export default defineComponent({
    components: { Tree, QuestionCircleOutlined },
    setup() {
      let base3d = null;
      let timer = null;
      let componentTree = ref(null);
      let checkedKeys = ref([]);
      const treeDiv = ref(null);
      const sb_bkx = ref(null);
      const sb_bky = ref(null);
      const gui_bkx = ref(null);
      const gui_bky = ref(null);
      const is_moving = ref(false);
      const is_gui_moving = ref(false);
      //贴图文件选项
      const mtlSearcher = ref(null);
      //详情说明
      const detailRef = ref(null);
      //选中的模型文件类型
      let fileType = 0;
      //模型文件地址
      const modalUri = ref('');

      const checkItems = (checKeys, e) => {
        //全选位置
        let selectItems = [];
        if (checKeys && checKeys.length > 0) {
          for (let i = 0; i < checKeys.length; i++) {
            selectItems.push(checKeys[i]);
          }
        }

        if (e.halfCheckedKeys && e.halfCheckedKeys.length > 0) {
          for (let i = 0; i < e.halfCheckedKeys.length; i++) {
            selectItems.push(e.halfCheckedKeys[i]);
          }
        }

        //触发构建隐藏事件 和 显示事件
        base3d.rerenderCom(selectItems);
      };

      // div拖动事件
      const mousedown = (event) => {
        //点击的时候取消margin属性重新计算位置
        treeDiv.value.style.margin = '0px';
        treeDiv.value.style.top = treeDiv.value.style.top + 40 + 'px';
        var startx = event.x;
        var starty = event.y;
        sb_bkx.value = startx - treeDiv.value.offsetLeft;
        sb_bky.value = starty - treeDiv.value.offsetTop;
        is_moving.value = true;
      };
      const mousemove = (event) => {
        var endx = event.x - sb_bkx.value;
        var endy = event.y - sb_bky.value;
        if (is_moving.value) {
          treeDiv.value.style.left = endx + 'px';
          treeDiv.value.style.top = endy + 'px';
        }
      };
      const mouseup = () => {
        is_moving.value = false;
      };
      //文件更换事件
      const changeFile = (file) => {
        const filesuffix = file.file.name.substring(file.file.name.lastIndexOf('.') + 1);
        if (filesuffix.search(new RegExp('obj', 'i')) !== -1) {
          //表示是OBJ文件
          fileType = 2;
          if (mtlSearcher.value) {
            mtlSearcher.value.style.display = 'inline-block';
          }
        } else if (filesuffix.search(new RegExp('glb|gltf', 'i')) !== -1) {
          //表示是OBJ文件
          fileType = 1;
          if (mtlSearcher.value) {
            mtlSearcher.value.style.display = 'none';
          }
        } else if (filesuffix.search(new RegExp('fbx', 'i')) !== -1) {
          //表示是OBJ文件
          fileType = 3;
          if (mtlSearcher.value) {
            mtlSearcher.value.style.display = 'none';
          }
        }
        let reader = new FileReader();
        reader.readAsArrayBuffer(file.file.originFileObj);
        let blob = null;
        reader.onload = (e) => {
          if (typeof e.target.result === 'object') {
            blob = new Blob([e.target.result]);
          } else {
            blob = e.target.result;
          }
          var href = window.URL.createObjectURL(blob); // 创建下载的链接
          modalUri.value = href;
          base3d.setModel(fileType, href, '');
          //定时任务 获取树
          timer = window.setInterval(() => {
            setTimeout(() => {
              let tree = base3d.getCompoentTree();
              if (tree && tree.length > 0) {
                componentTree.value = tree;
                for (let i = 0; i < componentTree.value.length; i++) {
                  checkedKeys.value.push(componentTree.value[i].key);
                }
                window.clearInterval(timer);
              }
            }, 0);
          }, 1000);
        };
      };
      //贴图文件选择
      const changeMtlFile = (file) => {
        const filesuffix = file.file.name.substring(file.file.name.lastIndexOf('.') + 1);
        if (filesuffix.search(new RegExp('mtl', 'i')) !== -1) {
          let reader = new FileReader();
          reader.readAsArrayBuffer(file.file.originFileObj);
          let blob = null;
          reader.onload = (e) => {
            if (typeof e.target.result === 'object') {
              blob = new Blob([e.target.result]);
            } else {
              blob = e.target.result;
            }
            var href = window.URL.createObjectURL(blob); // 创建下载的链接
            base3d.setModel(fileType, modalUri.value, href);
            //定时任务 获取树
            timer = window.setInterval(() => {
              setTimeout(() => {
                let tree = base3d.getCompoentTree();
                if (tree && tree.length > 0) {
                  componentTree.value = tree;
                  for (let i = 0; i < componentTree.value.length; i++) {
                    checkedKeys.value.push(componentTree.value[i].key);
                  }
                  window.clearInterval(timer);
                }
              }, 0);
            }, 1000);
          };
        } else {
          console.log('不支持的材质文件');
        }
      };
      //按照类型获取元素
      //可以获取 多个类型属性的 元素
      function getElementsByClass(oParent, target) {
        if (!oParent) {
          oParent = document;
        }

        var aEle = oParent.getElementsByTagName('*');
        var aResult = [];
        var reg = new RegExp('\\b(?!-)' + target + '(?!-)\\b', 'i');
        var i = 0;

        for (i = 0; i < aEle.length; i++) {
          if (reg.test(aEle[i].className)) {
            aResult.push(aEle[i]);
          }
        }

        return aResult;
      }
      //让GUI可动
      const guiMoveable = () => {
        let gui = getElementsByClass(null, 'dg main a');
        if (gui) {
          const mousedownEv = (e) => {
            var e = e || window.event; //要用event这个对象来获取鼠标的位置
            const left22 = gui[0].offsetLeft;
            const top22 = gui[0].offsetTop;
            gui[0].style.position = 'absolute';
            gui[0].style.margin = '0px';
            gui[0].style.top = top22 + 'px';
            gui[0].style.left = left22 + 'px';
            gui_bkx.value = e.clientX - gui[0].offsetLeft;
            gui_bky.value = e.clientY - gui[0].offsetTop;
            is_gui_moving.value = true; //设为true表示可以移动
          };
          const mousemoveEv = (e) => {
            if (is_gui_moving.value) {
              var e = e || window.event;
              var moveX = e.clientX - gui_bkx.value; //得到距离左边移动距离
              var moveY = e.clientY - gui_bky.value; //得到距离上边移动距离

              gui[0].style.left = moveX + 'px';
              gui[0].style.top = moveY + 'px';
            } else {
              return;
            }
          };
          const mouseupEv = () => {
            is_gui_moving.value = false;
          };

          gui[0].onmousedown = mousedownEv;
          gui[0].onmousemove = mousemoveEv;
          gui[0].onmouseup = mouseupEv;

          return true;
        } else {
          return false;
        }
      };
      const showDetail = () => {
        if (detailRef.value) {
          detailRef.value.style.display = 'inline-block';
        }
      };
      const closeDetail = () => {
        if (detailRef.value) {
          detailRef.value.style.display = 'none';
        }
      };
      onMounted(() => {
        base3d = new Base3d('#scene');
        //定时任务 修改Gui 窗口的属性 成功后删除定时任务
        timer = window.setInterval(() => {
          setTimeout(() => {
            if (guiMoveable()) {
              window.clearInterval(timer);
            }
          }, 0);
        }, 1000);
      });
      onBeforeUnmount(() => {
        base3d.clear();
      });
      return {
        componentTree,
        checkedKeys,
        checkItems,
        treeDiv,
        mousedown,
        mousemove,
        mouseup,
        changeFile,
        changeMtlFile,
        mtlSearcher,
        showDetail,
        closeDetail,
        detailRef,
      };
    },
  });
</script>

<style lang="less" scoped>
  * {
    margin: 0;
    padding: 0;
  }
  .tree_utils {
    position: absolute;
    width: 100%;
    background: rgba(29, 28, 28, 0.7) !important;
    color: rgb(15, 182, 233);
    ::v-deep(.ant-btn) {
      border: 0px;
      border-radius: 0px;
      background: transparent;
      color: rgb(15, 182, 233);
    }
    .items {
      margin-left: 5px;
      display: inline-block;
      width: auto;
      height: 30px;
    }
    .ver_line {
      margin-left: 5px;
      display: inline-block;
      width: 2px;
      height: 10px;
      background-color: rgba(46, 45, 45, 0.89);
    }
  }
  .tree_class {
    position: absolute;
    margin-top: 40px;
  }
  .tree_content {
    background: rgba(32, 31, 31, 0.6) !important;
    min-width: 300px;
    max-width: 300px;
    max-height: 600px;
    overflow: auto;
    &::-webkit-scrollbar {
      width: 5px;
      height: 5px;
    }
    &::-webkit-scrollbar-thumb {
      background-color: rgb(48, 47, 47) !important;
      // border-radius: 2px;
      box-shadow: inset 0 0 6px rgb(0 0 0 / 20%);
    }
    &::-webkit-scrollbar-track {
      background-color: transparent !important;
    }
    // 解决出现滚动条后 右下角出现的小白块
    &::-webkit-scrollbar-corner {
      background-color: transparent !important;
    }
  }
  .tree_title {
    background: rgba(29, 28, 28, 0.7) !important;
    color: whitesmoke;
    padding-left: 5px;
  }
  .detail {
    max-width: 300px;
    position: absolute;
    top: 22px;
    left: 22px;
    width: auto;
    height: auto;
    color: whitesmoke;
    background-color: rgba(0, 10, 40);
    opacity: 0.8;
    display: none;
    padding: 5px;
    //设置文本无法选中
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
  .tag {
    position: absolute;
    background-color: MidnightBlue;
    background-color: rgba(0, 10, 40);
    opacity: 0.8;
    font-size: 4px;
    color: aqua;
    padding: 1px 1px 1px;
    display: none;
    //设置文本无法选中
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
  }
  ::v-deep(.ant-tree) {
    background: transparent !important;
    color: whitesmoke;
    border-radius: 0px;
  }
</style>
// 设置GUI的样式
<style lang="less">
  .dg li:not(.folder) {
    cursor: auto;
    background: rgba(29, 28, 28, 0.7) !important;
    height: 27px;
    line-height: 17px !important;
    padding: 0 4px 0 5px;
  }
  .dg.main.a {
    margin-top: 120px;
    background-color: transparent;
  }
  .dg .c .slider {
    background: rgba(32, 31, 31, 0.6) !important;
  }
  .dg.main .close-button {
    background: rgba(29, 28, 28, 0.7) !important;
  }
</style>
